package com.pokermind.operator.engine;

import com.pokermind.common.log.PlainLog;
import com.pokermind.common.log.TimeCostLog;
import com.pokermind.model.dto.PokerAIRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 数学兜底引擎
 * 当AI超时时，基于数学分析快速给出保守决策
 *
 * 设计原则:
 * 1. 快速 (<50ms)
 * 2. 保守 (避免大损失)
 * 3. 合理 (基于EV、Equity、Pot Odds)
 * 4. 可解释 (有明确理由)
 *
 * @author PokerMind Team
 */
@Component
public class MathFallbackEngine {

    private static final Logger logger = LoggerFactory.getLogger(MathFallbackEngine.class);

    /**
     * 计算兜底决策
     *
     * @param request AI请求（包含所有牌局信息）
     * @return 数学兜底决策
     */
    public MathFallbackDecision calculate(PokerAIRequest request) {
        PlainLog log = new TimeCostLog("op", "math_fallback");

        try {
            // 1. 提取关键指标（使用实际金额）
            double equity = request.getHeroEquity() != null ? request.getHeroEquity() : 0.5;
            Double pot = request.getPot();
            Double stacks = request.getStacks();
            Double spr = request.getSpr();
            String street = request.getStreet();

            log.put("equity", String.format("%.3f", equity))
                .put("pot", pot != null ? String.format("%.0f", pot) : "null")
                .put("stacks", stacks != null ? String.format("%.0f", stacks) : "null")
                .put("spr", spr != null ? String.format("%.2f", spr) : "null")
                .put("street", street);

            // 2. 解析当前动作需求（使用实际金额）
            ActionContext ctx = parseActionContext(request);
            double toCall = ctx.toCall;
            boolean canCheck = ctx.canCheck;

            log.put("toCall", String.format("%.0f", toCall))
                .put("canCheck", canCheck);

            // 3. 决策逻辑（保守，使用实际金额）
            MathFallbackDecision decision = decideAction(equity, pot, stacks, spr, toCall, canCheck, street);

            log.put("action", decision.getAction())
                .put("size", decision.getSize())
                .put("reason", decision.getReason())
                .put("op_rslt", "success");

            logger.info(log.toString());

            return decision;

        } catch (Exception e) {
            log.put("op_rslt", "failed").put("error", e.getMessage());
            logger.error(log.toString(), e);

            // 极端兜底：最保守决策
            return getUltraConservativeDecision(request);
        }
    }

    /**
     * 决策逻辑（使用实际金额）
     */
    private MathFallbackDecision decideAction(double equity, Double pot, Double stacks, Double spr,
                                               double toCall, boolean canCheck, String street) {

        // === 场景1: 可以Check（无需跟注）===
        if (canCheck) {
            if (equity > 0.70) {
                // 牌力强，下注（底池的66%）
                double betSize = pot != null ? Math.round(pot * 0.66) : 100;
                return new MathFallbackDecision("bet", String.valueOf((int)betSize),
                    String.format("Strong equity %.2f, value bet", equity));
            } else if (equity > 0.55) {
                // 牌力不错，小注（底池的50%）
                double betSize = pot != null ? Math.round(pot * 0.5) : 50;
                return new MathFallbackDecision("bet", String.valueOf((int)betSize),
                    String.format("Good equity %.2f, conservative bet", equity));
            } else {
                // 牌力一般，过牌
                return new MathFallbackDecision("check", null,
                    String.format("Medium equity %.2f, check", equity));
            }
        }

        // === 场景2: 需要跟注 ===

        // 计算底池赔率
        double currentPot = (pot != null ? pot : 10.0);
        double potOdds = toCall / (currentPot + toCall);

        // 场景2.1: Equity远大于底池赔率 → Raise
        if (equity > potOdds + 0.30) {
            boolean lowSpr = (spr != null && spr < 3.0);
            if (lowSpr) {
                // SPR低，all-in
                String raiseSize = stacks != null ? String.valueOf(stacks.intValue()) : "200";
                return new MathFallbackDecision("raise", raiseSize,
                    String.format("Strong equity %.2f >> pot odds %.2f, low SPR", equity, potOdds));
            } else {
                // 加注到底池的66%
                double raiseSize = Math.round((currentPot + toCall) * 0.66 + toCall);
                return new MathFallbackDecision("raise", String.valueOf((int)raiseSize),
                    String.format("Strong equity %.2f >> pot odds %.2f", equity, potOdds));
            }
        }

        // 场景2.2: Equity明显大于底池赔率 → Call
        if (equity > potOdds + 0.15) {
            return new MathFallbackDecision("call", null,
                String.format("Equity %.2f > pot odds %.2f + margin", equity, potOdds));
        }

        // 场景2.3: Equity接近底池赔率 → 根据SPR决定
        if (equity > potOdds - 0.05) {
            if (spr != null && spr < 2.0) {
                // 筹码浅，已投入较多，all-in
                String raiseSize = stacks != null ? String.valueOf(stacks.intValue()) : "200";
                return new MathFallbackDecision("raise", raiseSize,
                    String.format("Committed pot, low SPR %.2f", spr));
            } else {
                // 勉强跟注
                return new MathFallbackDecision("call", null,
                    String.format("Marginal call, equity %.2f ≈ pot odds %.2f", equity, potOdds));
            }
        }

        // 场景2.4: Equity小于底池赔率 → Fold
        return new MathFallbackDecision("fold", null,
            String.format("Equity %.2f < pot odds %.2f, fold", equity, potOdds));
    }

    /**
     * 解析动作上下文（使用实际金额）
     */
    private ActionContext parseActionContext(PokerAIRequest request) {
        ActionContext ctx = new ActionContext();

        // 从potOddsNote中解析需要跟注的金额（直接使用美元）
        String note = request.getPotOddsNote();
        if (note != null && note.contains("需跟注$")) {
            try {
                int start = note.indexOf("需跟注$") + 4;
                int end = note.indexOf("，", start);
                if (end > start) {
                    double toCall = Double.parseDouble(note.substring(start, end));
                    ctx.toCall = toCall; // 直接使用美元金额
                    ctx.canCheck = false;
                    return ctx;
                }
            } catch (Exception e) {
                logger.debug("Failed to parse toCall from potOddsNote: {}", note);
            }
        } else if (note != null && note.contains("无需跟注")) {
            ctx.toCall = 0.0;
            ctx.canCheck = true;
            return ctx;
        }

        // 默认：可以check
        ctx.toCall = 0.0;
        ctx.canCheck = true;
        return ctx;
    }

    /**
     * 极端兜底：最保守决策
     */
    private MathFallbackDecision getUltraConservativeDecision(PokerAIRequest request) {
        ActionContext ctx = parseActionContext(request);

        if (ctx.canCheck) {
            // 可以check就check
            return new MathFallbackDecision("check", null,
                "Ultra conservative fallback - check");
        } else {
            // 需要跟注就fold（最保守）
            return new MathFallbackDecision("fold", null,
                "Ultra conservative fallback - fold");
        }
    }

    /**
     * 动作上下文（使用实际金额）
     */
    private static class ActionContext {
        double toCall = 0.0;
        boolean canCheck = true;
    }
}

